package mdb

import (
	"fmt"
	"gitee.com/dennis-mxx/mxx-core/mutil"
	"strings"
)

const ShowSql = false

type query struct {
	TableName string
	selectSql strings.Builder
	whereSql  strings.Builder
	limit     string
	orderBy   string
	param     []interface{}
	semantics string
}

func NewSelect(tableName string) *query {
	var slice []interface{}
	return &query{TableName: tableName, selectSql: strings.Builder{}, whereSql: strings.Builder{}, param: slice, semantics: "and"}
}

func (domain *query) SelectAll() *query {
	sqlSelect := &domain.selectSql
	sqlSelect.WriteString("select * from ")
	sqlSelect.WriteString(domain.TableName)
	return domain
}
func (domain *query) Select(column ...string) *query {
	sqlSelect := &domain.selectSql
	sqlSelect.WriteString("select ")
	len := len(column)
	for i, v := range column {
		sqlSelect.WriteString(" ")
		sqlSelect.WriteString(v)
		if i+1 < len {
			sqlSelect.WriteString(" ,")
		}
	}
	sqlSelect.WriteString(" from ")
	sqlSelect.WriteString(domain.TableName)
	return domain
}

func (domain *query) Equal(param map[string]interface{}) *query {
	domain.where("=", param)
	return domain
}
func (domain *query) LessThan(param map[string]interface{}) *query {
	domain.where("<", param)
	return domain
}
func (domain *query) LessThanEqual(param map[string]interface{}) *query {
	domain.where("<=", param)
	return domain
}
func (domain *query) GreaterThan(param map[string]interface{}) *query {
	domain.where(">", param)
	return domain
}
func (domain *query) GreaterThanEqual(param map[string]interface{}) *query {
	domain.where(">=", param)
	return domain
}
func (domain *query) NotEqual(param map[string]interface{}) *query {
	domain.where("<>", param)
	return domain
}
func (domain *query) RightLike(param map[string]interface{}) *query {
	for k, v := range param {
		if mutil.Strings.NotNull(v) {
			domain.writeWhere(domain.semantics, fmt.Sprintf("%s like ? ", k))
			domain.param = append(domain.param, fmt.Sprintf("%v%s", v, "%"))
		}
	}
	return domain
}
func (domain *query) LeftLike(param map[string]interface{}) *query {
	for k, v := range param {
		if mutil.Strings.NotNull(v) {
			domain.writeWhere(domain.semantics, fmt.Sprintf("%s  like  ? ", k))
			domain.param = append(domain.param, fmt.Sprintf("%s%v", "%", v))
		}
	}
	return domain
}
func (domain *query) Like(param map[string]interface{}) *query {
	for k, v := range param {
		if mutil.Strings.NotNull(v) {
			domain.writeWhere(domain.semantics, fmt.Sprintf("%s like ? ", k))
			domain.param = append(domain.param, fmt.Sprintf("%s%v%s", "%", v, "%"))
		}
	}
	return domain
}
func (domain *query) Between(column string, val1 interface{}, val2 interface{}) *query {
	if mutil.Strings.NotNull(val1) && mutil.Strings.NotNull(val2) {
		domain.writeWhere(domain.semantics, fmt.Sprintf("%s between ?,? ", column))
		domain.param = append(domain.param, val1, val2)
	}
	return domain

}

func (domain *query) where(connector string, param map[string]interface{}) *query {
	for k, v := range param {
		if mutil.Strings.NotNull(v) {
			domain.writeWhere(domain.semantics, fmt.Sprintf("%s %s ? ", k, connector))
			domain.param = append(domain.param, v)
		}
	}
	return domain
}
func (domain *query) writeWhere(semantics string, str string) *query {
	if domain.whereSql.Len() != 0 {
		domain.whereSql.WriteString(semantics)
		domain.whereSql.WriteString(" ")
	}
	domain.whereSql.WriteString(str)
	return domain
}
func (domain *query) Where(sql string) *query {
	domain.whereSql.WriteString(sql)
	return domain
}

func (domain *query) CountSql() string {
	if domain.whereSql.Len() == 0 {
		return fmt.Sprintf("select count(0) as count from %s ", domain.TableName)
	} else {
		return fmt.Sprintf("select count(0) as count from %s where %s", domain.TableName, domain.whereSql.String())
	}

}
func (domain *query) SelectParam() []interface{} {
	return domain.param
}
func (domain *query) SelectSql() string {
	if domain.whereSql.Len() == 0 {
		return fmt.Sprintf("%s%s%s", domain.selectSql.String(), domain.orderBy, domain.limit)
	} else {
		return fmt.Sprintf("%s where %s%s%s", domain.selectSql.String(), domain.whereSql.String(), domain.orderBy, domain.limit)
	}
}
func (domain *query) WhereSql() string {
	if domain.whereSql.Len() == 0 {
		return domain.whereSql.String()
	} else {

		return fmt.Sprintf(" where %s", domain.whereSql.String())
	}

}
func (domain *query) Desc(column string) *query {
	domain.orderBy = fmt.Sprintf(" order by %s desc ", column)
	return domain
}
func (domain *query) Asc(column string) *query {
	domain.orderBy = fmt.Sprintf(" order by %s asc ", column)
	return domain
}
func (domain *query) Limit(page int, size int) *query {
	domain.limit = fmt.Sprintf(" limit %v , %v ", page, size)
	return domain
}
func (domain *query) And() *query {
	domain.semantics = "and"
	return domain
}
func (domain *query) Or() *query {
	domain.semantics = "or"
	return domain
}
